package com.atguigu.stgy.common.interceptor;

import com.atguigu.stgy.common.exception.StgyException;
import com.atguigu.stgy.common.util.JwtUtils;
import com.atguigu.stgy.model.result.ResultCodeEnum;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class StgyAuthInterceptor implements HandlerInterceptor {
    //线程安全的数据：线程私有的数据 可以不考虑并发安全问题(不用加锁)
    public static ThreadLocal<Long> THREAD_LOCAL = new ThreadLocal<>();
    //透传数据的Map: map会被并发的多线程同时使用，会出现并发安全问题   可以使用并发容器类 支持高并发 数据安全的map  ConcurrentHashMap
//    public static Map<Thread,Long> AUTH_MAP = new ConcurrentHashMap<>();
    //map中会存入每个线程对应的登录状态的id，如果线程执行结束不清空缓存数据 会导致map中的数据越来越多
    //  当jvm内存不足时会触发GC，AUTH_MAP持有引用的数据 是强引用 不能被回收 导致频繁GC
    //可以在线程执行结束时 移除map中使用过的数据
    /*
        在ds的请求 调用 controller 的接口方法前执行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //预检请求直接放行
        if(request.getMethod().equalsIgnoreCase("OPTIONS")){
            return true;
        }
        //校验登录状态
        //1、获取请求头中的 access_token
        String token = request.getHeader("access_token");
        //2、判断token是否有效：有效放行 无效抛出异常
        try {
            Jws<Claims> claimsJws = JwtUtils.parseToken(token);
//            AUTH_MAP.put(Thread.currentThread(),claimsJws.getBody().get("id",Long.class) );
            //threadLocal设置数据：
            // 先获取线程对象的成员属性map，然后使用ThreadLocal对象作为键 传入的值作为值 存到map中
            THREAD_LOCAL.set(claimsJws.getBody().get("id",Long.class));
            return true;
        } catch (Exception e) {//catch的异常对象包含了异常发生时的堆栈日志
            //3、token无效
//            throw new RuntimeException("登录状态失效"); //抛出自己创建的异常对象不包含异常堆栈日志
            throw new StgyException(ResultCodeEnum.APP_LOGIN_AUTH);
        }

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//        AUTH_MAP.remove(Thread.currentThread());
        //移除数据
        //  先获取线程对象的成员属性map，使用ThreadLocal对象作为建移除数据
        THREAD_LOCAL.remove();
    }
}
